package com.agileboot.domain.exam.db;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.utils.CommonUtils;
import com.agileboot.domain.bank.query.ExamQuery;
import com.agileboot.domain.exam.form.ExamForm;
import com.agileboot.domain.exam.form.PaperData;
import com.agileboot.domain.exam.query.ExamPaperQuery;
import com.agileboot.domain.exam.vo.AddExamByBankVo;
import com.agileboot.domain.exam.vo.AddExamByQuestionVo;
import com.agileboot.domain.exam.vo.ExamQueryVo;
import com.agileboot.domain.examquestion.db.ExamQuestion;
import com.agileboot.domain.examquestion.db.ExamQuestionMapper;
import com.agileboot.domain.examrecord.db.ExamRecord;
import com.agileboot.domain.examrecord.db.ExamRecordMapper;
import com.agileboot.domain.examrecord.db.ExamRecordService;
import com.agileboot.domain.question.db.Question;
import com.agileboot.domain.question.db.QuestionMapper;
import com.agileboot.infrastructure.cache.RedisUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * @author lx
 * @implNote 2022/2/26
 */
@Service
public class ExamServiceImpl extends ServiceImpl<ExamMapper, Exam> implements ExamService {
    @Autowired
    private  QuestionMapper questionMapper;
    @Autowired
    private  ExamMapper examMapper;
    @Autowired
    private ExamRecordMapper examRecordMapper;
    @Autowired
    private  ExamQuestionMapper examQuestionMapper;

    private  RedisUtil redisUtil;

    @Override
    public PageDTO<Exam> getExamPage(ExamQueryVo examQueryVo) {
        QueryWrapper<Exam> wrapper = new QueryWrapper<>();

        CommonUtils.setEqualsQueryWrapper(wrapper, Collections.singletonMap("type", examQueryVo.getExamType()));
        CommonUtils.setLikeWrapper(wrapper, Collections.singletonMap("exam_name", examQueryVo.getExamName()));
        if (examQueryVo.getStartTime() != null) {
            wrapper.gt("start_time", examQueryVo.getStartTime().substring(0, examQueryVo.getStartTime().indexOf("T")));
        }
        if (examQueryVo.getEndTime() != null) {
            wrapper.lt("end_time", examQueryVo.getEndTime().substring(0, examQueryVo.getEndTime().indexOf("T")));
        }
        IPage<Exam> page = examMapper.selectPage(new Page<>(examQueryVo.getPageNo(), examQueryVo.getPageSize()), wrapper);

        return new PageDTO<>(page.getRecords());
    }

    //    @Cache(prefix = "examInfo", suffix = "#examId", ttl = 4, randomTime = 2, timeUnit = TimeUnit.HOURS)
    @Override
    public AddExamByQuestionVo getExamInfoById(Integer examId) {
        // 构造传递给前端的考试组合对象
        Exam exam = Optional.ofNullable(examMapper.selectById(examId))
                .orElseThrow(() -> new ApiException(ErrorCode.Business.LOGIN_CAPTCHA_CODE_WRONG));
        AddExamByQuestionVo addExamByQuestionVo = AddExamByQuestionVo.builder()
                .examDesc(exam.getExamDesc())
                .examDuration(exam.getDuration())
                .examId(examId)
                .examName(exam.getExamName())
                .passScore(exam.getPassScore())
                .totalScore(exam.getTotalScore())
                .startTime(exam.getStartTime())
                .endTime(exam.getEndTime())
                .type(exam.getType())
                .password(exam.getPassword())
                .status(exam.getStatus())
                .build();

        // 考试中题目的对象
        ExamQuestion examQuestion = examQuestionMapper.selectOne(new QueryWrapper<ExamQuestion>().eq("exam_id", examId));
        addExamByQuestionVo.setQuestionIds(examQuestion.getQuestionIds());
        addExamByQuestionVo.setScores(examQuestion.getScores());
        return addExamByQuestionVo;
    }

    @Override
    public void operationExam(Integer type, String ids) {
        String[] id = ids.split(",");
        switch (type) {
            case 1:
                setExamStatus(id, 1);
                break;
            case 2:
                setExamStatus(id, 2);
                break;
            case 3:
                Map<String, Object> map = new HashMap<>();
                for (String s : id) {
                    map.clear();
                    map.put("exam_id", Integer.parseInt(s));
                    examMapper.deleteByMap(map);
                    examQuestionMapper.deleteByMap(map);
//                    redisUtil.del("examInfo:" + s);
                }
                break;
            default:
                throw new ApiException(ErrorCode.Business.LOGIN_CAPTCHA_CODE_EXPIRE);
        }
    }

    @Transactional
    @Override
    public void addExamByBank(AddExamByBankVo addExamByBankVo) {
        Exam exam = new Exam();
        exam.setStatus(addExamByBankVo.getStatus());
        exam.setDuration(addExamByBankVo.getExamDuration());
        if (addExamByBankVo.getEndTime() != null) exam.setEndTime(addExamByBankVo.getEndTime());
        if (addExamByBankVo.getStartTime() != null) exam.setStartTime(addExamByBankVo.getStartTime());
        exam.setExamDesc(addExamByBankVo.getExamDesc());
        exam.setExamName(addExamByBankVo.getExamName());
        exam.setPassScore(addExamByBankVo.getPassScore());
        exam.setType(addExamByBankVo.getType());
        // 设置密码如果有
        if (addExamByBankVo.getPassword() != null) {
            exam.setPassword(addExamByBankVo.getPassword());
        }
        // 设置id
        ExamQuestion examQuestion = buildExamQuestion(exam);
        // 设置题目id字符串
        HashSet<Integer> set = new HashSet<>();
        String[] bankNames = addExamByBankVo.getBankNames().split(",");

        for (String bankName : bankNames) {
            List<Question> questions = questionMapper.selectList(new QueryWrapper<Question>().like("qu_bank_name", bankName));
            for (Question question : questions) {
                set.add(question.getId());
            }
        }
        String quIds = set.toString().substring(1, set.toString().length() - 1).replaceAll(" ", "");
        System.out.println(quIds);
        examQuestion.setQuestionIds(quIds);
        // 设置每一题的分数
        String[] s = quIds.split(",");
        // 总分
        int totalScore = 0;
        StringBuilder sf = new StringBuilder();
        for (String s1 : s) {
            Question question = questionMapper.selectById(Integer.parseInt(s1));
            if (question.getQuType() == 1) {
                sf.append(addExamByBankVo.getSingleScore()).append(",");
                totalScore += addExamByBankVo.getSingleScore();
            } else if (question.getQuType() == 2) {
                sf.append(addExamByBankVo.getMultipleScore()).append(",");
                totalScore += addExamByBankVo.getMultipleScore();
            } else if (question.getQuType() == 3) {
                sf.append(addExamByBankVo.getJudgeScore()).append(",");
                totalScore += addExamByBankVo.getJudgeScore();
            } else if (question.getQuType() == 4) {
                sf.append(addExamByBankVo.getShortScore()).append(",");
                totalScore += addExamByBankVo.getShortScore();
            }
        }
        examQuestion.setScores(sf.substring(0, sf.toString().length() - 1));
        // 设置总成绩
        exam.setTotalScore(totalScore);

        examMapper.insert(exam);
        examQuestionMapper.insert(examQuestion);
    }

    @Transactional
    @Override
    public void addExamByQuestionList(AddExamByQuestionVo addExamByQuestionVo) {
        Exam exam = new Exam();
        exam.setTotalScore(addExamByQuestionVo.getTotalScore());
        exam.setType(addExamByQuestionVo.getType());
        exam.setPassScore(addExamByQuestionVo.getPassScore());
        if (addExamByQuestionVo.getEndTime() != null) exam.setEndTime(addExamByQuestionVo.getEndTime());
        if (addExamByQuestionVo.getStartTime() != null) exam.setStartTime(addExamByQuestionVo.getStartTime());
        exam.setExamDesc(addExamByQuestionVo.getExamDesc());
        exam.setExamName(addExamByQuestionVo.getExamName());
        exam.setDuration(addExamByQuestionVo.getExamDuration());
        // 设置密码如果有
        if (addExamByQuestionVo.getPassword() != null) {
            exam.setPassword(addExamByQuestionVo.getPassword());
        }
        exam.setStatus(addExamByQuestionVo.getStatus());
        // 设置id
        ExamQuestion examQuestion = buildExamQuestion(exam);
        examQuestion.setScores(addExamByQuestionVo.getScores());
        examQuestion.setQuestionIds(addExamByQuestionVo.getQuestionIds());

        examMapper.insert(exam);
        examQuestionMapper.insert(examQuestion);
    }

    @Override
    public void updateExamInfo(AddExamByQuestionVo addExamByQuestionVo) {
        Exam exam = new Exam();
        exam.setTotalScore(addExamByQuestionVo.getTotalScore());
        exam.setType(addExamByQuestionVo.getType());
        exam.setPassScore(addExamByQuestionVo.getPassScore());
        exam.setEndTime(addExamByQuestionVo.getEndTime());
        exam.setStartTime(addExamByQuestionVo.getStartTime());
        exam.setExamDesc(addExamByQuestionVo.getExamDesc());
        exam.setExamName(addExamByQuestionVo.getExamName());
        exam.setDuration(addExamByQuestionVo.getExamDuration());
        // 设置密码如果有
        if (addExamByQuestionVo.getPassword() != null) {
            exam.setPassword(addExamByQuestionVo.getPassword());
        } else {
            exam.setPassword(null);
        }
        exam.setStatus(addExamByQuestionVo.getStatus());
        exam.setExamId(addExamByQuestionVo.getExamId());
        // 设置考试的题目和分值信息
        ExamQuestion examQuestion = new ExamQuestion();
        examQuestion.setExamId(addExamByQuestionVo.getExamId());
        examQuestion.setScores(addExamByQuestionVo.getScores());
        examQuestion.setQuestionIds(addExamByQuestionVo.getQuestionIds());

        examMapper.update(exam, new UpdateWrapper<Exam>().eq("exam_id", exam.getExamId()));
        examQuestionMapper.update(examQuestion, new UpdateWrapper<ExamQuestion>().eq("exam_id", exam.getExamId()));
        // 移除缓存
//        redisUtil.del("examInfo:" + exam.getExamId());
    }

    @Override
    public List<String> getExamPassRateEchartData() {
        List<Exam> exams = examMapper.selectList(null);
//        List<ExamRecord> examRecords = examRecordService.list(new QueryWrapper<ExamRecord>().isNotNull("total_score"));
        List<ExamRecord> examRecords = Collections.EMPTY_LIST;
        // 考试的名称
        String[] examNames = new String[exams.size()];
        // 考试通过率
        double[] passRates = new double[exams.size()];

        double total;
        double pass;
        for (int i = 0; i < exams.size(); i++) {
            examNames[i] = exams.get(i).getExamName();
            total = 0;
            pass = 0;
            for (ExamRecord examRecord : examRecords) {
                if (Objects.equals(examRecord.getExamId(), exams.get(i).getExamId())) {
                    total++;
                    if (examRecord.getTotalScore() >= exams.get(i).getPassScore()) pass++;
                }
            }
            passRates[i] = pass / total;
        }
        for (int i = 0; i < passRates.length; i++) {
            if (Double.isNaN(passRates[i])) passRates[i] = 0;
        }
        List<String> list = new ArrayList<>();
        String res1 = Arrays.toString(examNames);
        String res2 = Arrays.toString(passRates);
        list.add(res1.substring(1, res1.length() - 1).replaceAll(" ", ""));
        list.add(res2.substring(1, res2.length() - 1).replaceAll(" ", ""));
        return list;
    }

    @Override
    public List<String> getExamNumbersEchartData() {
        List<Exam> exams = examMapper.selectList(null);
        List<ExamRecord> examRecords = Collections.EMPTY_LIST;
//                examRecordService.list(null);
        // 考试的名称
        String[] examNames = new String[exams.size()];
        // 考试的考试次数
        String[] examNumbers = new String[exams.size()];

        int cur;
        for (int i = 0; i < exams.size(); i++) {
            examNames[i] = exams.get(i).getExamName();
            cur = 0;
            for (ExamRecord examRecord : examRecords) {
                if (Objects.equals(examRecord.getExamId(), exams.get(i).getExamId())) {
                    cur++;
                }
            }
            examNumbers[i] = cur + "";
        }
        List<String> list = new ArrayList<>();
        String res1 = Arrays.toString(examNames);
        String res2 = Arrays.toString(examNumbers);
        list.add(res1.substring(1, res1.length() - 1).replaceAll(" ", ""));
        list.add(res2.substring(1, res2.length() - 1).replaceAll(" ", ""));
        return list;
    }

    @Override
    public PageDTO<ExamForm> getExam(ExamPaperQuery query) {
        Page<Exam> page = page(query.toPage(), query.toQueryWrapper());
        Page<ExamForm> examFormPage = new Page<>(query.toPage().getCurrent(), query.toPage().getSize());
        BeanUtils.copyProperties(page, examFormPage);
        List<Exam> records = page.getRecords();
        List<ExamForm> list = new ArrayList<>();
        for (Exam record : records) {
            ExamForm examForm = new ExamForm();
            BeanUtils.copyProperties(record,examForm);
            ExamQuestion examQuestion = examQuestionMapper.selectOne(Wrappers.lambdaQuery(ExamQuestion.class).eq(ExamQuestion::getExamId, record.getExamId()));
            if (StringUtils.isEmpty(examQuestion.getQuestionIds())){
                list.add(examForm);
                continue;
            }
            String[] split = examQuestion.getQuestionIds().split(",");
            List<Question> questions = questionMapper.selectBatchIds(Arrays.asList(split));
            List<PaperData> paperData = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(questions)){
                for (Question question : questions) {
                    PaperData data = new PaperData();
                    BeanUtils.copyProperties(question,data);
                    paperData.add(data);
                }
            }
            examForm.setPaperData(paperData);
            list.add(examForm);
        }
        examFormPage.setRecords(list);
        return new PageDTO<>(examFormPage);
    }

    @Override
    public void addExam(ExamForm examForm) {
        Assert.isTrue(Objects.nonNull(examForm),"请求参数为空");
        Exam exam = new Exam();
        BeanUtil.copyProperties(examForm,exam);
        exam.setStatus(1);
        if (CollectionUtils.isNotEmpty(examForm.getPaperData())){
            //获取考试总分
            int sum = examForm.getPaperData().stream().mapToInt(PaperData::getScore).sum();
            exam.setTotalScore(sum);
        }
        examMapper.insert(exam);
        ExamQuestion examQuestion = new ExamQuestion();
        examQuestion.setExamId(exam.getExamId());
        //获取试卷中所有试题id集合的字符串
        if (CollectionUtils.isNotEmpty(examForm.getPaperData())){
            //填充试题的id列表
            String questionIds = examForm.getPaperData().stream().map(paperData -> paperData.getId().toString()).collect(Collectors.joining(","));
            examQuestion.setQuestionIds(questionIds);
            //填充试题的对应的分数
            String score = examForm.getPaperData().stream().map(paperData -> paperData.getScore().toString()).collect(Collectors.joining(","));
            examQuestion.setScores(score);
        }
        //获取每道题对应的分数
        examQuestionMapper.insert(examQuestion);
    }

    @Override
    public void deleteExam(String ids) {
        Assert.isTrue(StringUtils.isNotEmpty(ids),"参数不能为空");
        String[] split = ids.split(",");
        List<String> strings = Arrays.asList(split);
        baseMapper.deleteBatchIds(strings);
    }

    @Override
    public void updateExam(Integer id, ExamForm examForm) {
        Assert.isTrue(Objects.nonNull(examForm),"请求参数为空");
        Exam exam = new Exam();
        BeanUtil.copyProperties(examForm,exam);
        exam.setStatus(1);
        if (CollectionUtils.isNotEmpty(examForm.getPaperData())){
            //获取考试总分
            int sum = examForm.getPaperData().stream().mapToInt(PaperData::getScore).sum();
            exam.setTotalScore(sum);
        }
        exam.setExamId(id);
        examMapper.updateById(exam);
        ExamQuestion examQuestion = new ExamQuestion();
        //获取试卷中所有试题id集合的字符串
        if (CollectionUtils.isNotEmpty(examForm.getPaperData())){
            //填充试题的id列表
            String questionIds = examForm.getPaperData().stream().map(paperData -> paperData.getId().toString()).collect(Collectors.joining(","));
            examQuestion.setQuestionIds(questionIds);
            //填充试题的对应的分数
            String score = examForm.getPaperData().stream().map(paperData -> paperData.getScore().toString()).collect(Collectors.joining(","));
            examQuestion.setScores(score);
        }
        //获取每道题对应的分数
        examQuestionMapper.update(examQuestion,Wrappers.lambdaQuery(ExamQuestion.class).eq(ExamQuestion::getExamId,id));
    }

    @Override
    public List<PaperData> getPaperData(Integer id) {
        ExamQuestion examQuestion = examQuestionMapper.selectOne(Wrappers.lambdaQuery(ExamQuestion.class).eq(ExamQuestion::getExamId, id));
        if (StringUtils.isEmpty(examQuestion.getQuestionIds())){
            return Collections.emptyList();
        }
        String[] split = examQuestion.getQuestionIds().split(",");
        List<String> scores = Arrays.asList(examQuestion.getScores().split(","));
        List<Question> questions = questionMapper.selectBatchIds(Arrays.asList(split));
        List<PaperData> paperData = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(questions)){
            for (int i = 0; i < questions.size(); i++) {
                PaperData data = new PaperData();
                BeanUtils.copyProperties(questions.get(i),data);
                data.setScore(Integer.parseInt(scores.get(i)));
                paperData.add(data);
            }
        }
        return paperData;
    }

    @Override
    public ExamRecord getExamDetailInfoById(Integer recordId) {
        return examRecordMapper.selectById(recordId);
    }

    private ExamQuestion buildExamQuestion(Exam exam) {
        List<Exam> examList = examMapper.selectList(null);
        int id = 0;
        if (examList.size() != 0) {
            id = examList.get(examList.size() - 1).getExamId() + 1;
        }
        exam.setExamId(id);
        ExamQuestion examQuestion = new ExamQuestion();
        examQuestion.setExamId(id);
        return examQuestion;
    }

    private void setExamStatus(String[] id, int status) {
        for (String s : id) {
            Exam exam = examMapper.selectOne(new QueryWrapper<Exam>().eq("exam_id", Integer.parseInt(s)));
            exam.setStatus(status);
            examMapper.update(exam, new UpdateWrapper<Exam>().eq("exam_id", s));
        }
    }
}
